package cluster

import (
	"encoding/json"
	"github.com/samuel/go-zookeeper/zk"
	log "github.com/sirupsen/logrus"
	"xc/app/zookeeper"
)

type NodeTask struct {
	path  string   //zk路径
	data  []byte   //zk数据
	flags int32    //zk标示
	acl   []zk.ACL //zk权限
}

var nodeTask *NodeTask

//InitNodeTask 初始化任务
func InitNodeTask() {
	nt := new(NodeTask)
	nt.initData()
	nt.check()

	nodeTask = nt
}

func (nt *NodeTask) initData() {
	nt.path = zookeeper.GetNodeTaskPath()
	nt.data = []byte("")
	nt.acl = zk.WorldACL(zk.PermAll)
	nt.flags = 0
}

//check 检查节点任务
func (nt *NodeTask) check() {
	exist, _, err := zookeeper.Connect().Exists(nt.path)
	if err != nil {
		log.Panic("[node_task]", err.Error())
	}
	if !exist {
		log.Info("[node_task]任务节点不存在")

		ret, err := zookeeper.Connect().Create(nt.path, nt.data, nt.flags, nt.acl)
		if err != nil {
			log.Panic("[node_task]任务节点创建失败")
		}
		log.Info("[node_task]任务节点创建成功:", ret)
	} else {
		log.Info("[node_task]任务节点已存在")
	}
}

func NodeTaskWatch() {
	nodeTask.watch()
}

// watch 监听node task信息变化
//
// 仅当事件为内容变化才做出变化响应,当发生
func (nt *NodeTask) watch() {
	_, _, watchEvent, err := zookeeper.Connect().GetW(nt.path)
	if err != nil {
		panic(err)
	}

	select {
	case nodeEvent := <-watchEvent:
		{
			log.Info("[node_task]监听到变化的路径:", nodeEvent.Path)
			log.Info("[node_task]监听到变化的类型:", nodeEvent.Type.String())

			switch nodeEvent.Type {
			case zk.EventNodeDataChanged:
				// 节点工作
				nt.doWork()

				// 循环监听
				nt.watch()
			case zk.EventNodeDeleted:
				log.Info("===========    警告️    ===========")
				log.Info("[node_task]监听到task被删除", nodeEvent.Path)
				log.Info("===========    警告️    ===========")
			default:
				log.Info("[task]监听到未知事件", nodeEvent)
			}
		}
	}
}

func (nt *NodeTask) doWork() {
	worker.AdjustNodeTaskWork()
}

// GetNodeTaskList 获取node task信息
// 数据格式 {"0000000065":{"test01":3,"test02":2}}
func (nt *NodeTask) GetNodeTaskList() (map[string]map[string]int, *zk.Stat) {
	data, info, err := zookeeper.Connect().Get(nt.path)

	if err != nil {
		log.Info("[node_task]获取node task信息失败")
		return make(map[string]map[string]int), info
	}

	nodeTaskList := make(map[string]map[string]int) //最大支持100个节点

	if len(data) != 0 {
		err = json.Unmarshal(data, &nodeTaskList)
		if err != nil {
			log.Panic("[node_task]", err)
		}
	}

	return nodeTaskList, info
}

//UpdateNodeTaskForZookeeper 更新变更的node task信息到zookeeper
func (nt *NodeTask) UpdateNodeTaskForZookeeper(nodesTaskArray map[string]map[string]int) {
	data, info := nt.GetNodeTaskList()

	var isChange = 0
	for k, v := range nodesTaskArray {
		// 判断 map[string] 是否相等
		if _, ok := data[k]; ok {
			for kk, vv := range v {
				// 判断 map[string]map[string] 是否相等
				if _, okk := data[k][kk]; okk {
					// 判断 map[string]map[string]int 是否相等
					if vv == data[k][kk] {
						continue
					} else {
						isChange = 1
						break
					}
				} else {
					isChange = 1
					break
				}
			}
		} else {
			isChange = 1
			break
		}
	}
	if isChange == 0 {
		log.Info("[node_task]任务无变化，不需要任何更新")
	} else {
		nodeTaskString, _ := json.Marshal(nodesTaskArray)
		_, errSet := zookeeper.Connect().Set(nt.path, nodeTaskString, info.Version)
		if errSet != nil {
			log.Info("[node_task]", errSet)
		}
	}
}
